﻿using System;
using GeoAPI.Geometries;
using NetTopologySuite.Geometries;
using NetTopologySuite.Geometries.Utilities;

namespace NetTopologySuite.Precision
{
	public class GeometryPrecisionReducer
	{
		public static IGeometry Reduce(IGeometry g, IPrecisionModel precModel)
		{
			return new GeometryPrecisionReducer(precModel).Reduce(g);
		}

		public static IGeometry ReducePointwise(IGeometry g, IPrecisionModel precModel)
		{
			return new GeometryPrecisionReducer(precModel)
			{
				Pointwise = true
			}.Reduce(g);
		}

		public GeometryPrecisionReducer(IPrecisionModel pm)
		{
			this._targetPrecModel = pm;
		}

		public bool RemoveCollapsedComponents
		{
			get
			{
				return this._removeCollapsed;
			}
			set
			{
				this._removeCollapsed = value;
			}
		}

		public bool ChangePrecisionModel
		{
			get
			{
				return this._changePrecisionModel;
			}
			set
			{
				this._changePrecisionModel = value;
			}
		}

		public bool Pointwise
		{
			get
			{
				return this._isPointwise;
			}
			set
			{
				this._isPointwise = value;
			}
		}

		public IGeometry Reduce(IGeometry geom)
		{
			IGeometry geometry = this.ReducePointwise(geom);
			if (this._isPointwise)
			{
				return geometry;
			}
			if (!(geometry is IPolygonal))
			{
				return geometry;
			}
			if (geometry.IsValid)
			{
				return geometry;
			}
			return this.FixPolygonalTopology(geometry);
		}

		private IGeometry ReducePointwise(IGeometry geom)
		{
			GeometryEditor geometryEditor;
			if (this._changePrecisionModel)
			{
				geometryEditor = new GeometryEditor(GeometryPrecisionReducer.CreateFactory(geom.Factory, this._targetPrecModel));
			}
			else
			{
				geometryEditor = new GeometryEditor();
			}
			bool removeCollapsed = this._removeCollapsed;
			if (geom.Dimension >= Dimension.Surface)
			{
				removeCollapsed = true;
			}
			return geometryEditor.Edit(geom, new PrecisionReducerCoordinateOperation(this._targetPrecModel, removeCollapsed));
		}

		private IGeometry FixPolygonalTopology(IGeometry geom)
		{
			IGeometry geometry = geom;
			if (!this._changePrecisionModel)
			{
				geometry = GeometryPrecisionReducer.ChangePrecModel(geom, this._targetPrecModel);
			}
			IGeometry geometry2 = geometry.Buffer(0.0);
			IGeometry result = geometry2;
			if (!this._changePrecisionModel)
			{
				result = geom.Factory.CreateGeometry(geometry2);
			}
			return result;
		}

		private static IGeometry ChangePrecModel(IGeometry geom, IPrecisionModel pm)
		{
			return GeometryPrecisionReducer.CreateEditor(geom.Factory, pm).Edit(geom, new GeometryEditor.NoOpGeometryOperation());
		}

		private static GeometryEditor CreateEditor(IGeometryFactory geomFactory, IPrecisionModel newPrecModel)
		{
			if (geomFactory.PrecisionModel == newPrecModel)
			{
				return new GeometryEditor();
			}
			return new GeometryEditor(GeometryPrecisionReducer.CreateFactory(geomFactory, newPrecModel));
		}

		private static IGeometryFactory CreateFactory(IGeometryFactory inputFactory, IPrecisionModel pm)
		{
			return new GeometryFactory(pm, inputFactory.SRID, inputFactory.CoordinateSequenceFactory);
		}

		private readonly IPrecisionModel _targetPrecModel;

		private bool _removeCollapsed = true;

		private bool _changePrecisionModel;

		private bool _isPointwise;
	}
}
